package cz.boxdesign.library.web;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.view.RedirectView;

import cz.boxdesign.library.common.dao.DatabaseOperationException;
import cz.boxdesign.library.entity.Author;
import cz.boxdesign.library.entity.Book;
import cz.boxdesign.library.entity.Napsal;
import cz.boxdesign.library.service.CommonService;
import cz.boxdesign.library.web.validation.AutorValidator;
import cz.boxdesign.library.web.view.AuthorView;
import cz.boxdesign.library.web.view.BookView;

/**
 * 
 * @author jlattenberk
 * 
 */
@Controller
@RequestMapping("/authors")
public class AuthorController extends AbstractController {

	protected final Log log = LogFactory.getLog(AuthorController.class);

	@Autowired
	@Qualifier(value = "autorService")
	CommonService<Author> autorService;

	@Autowired
	@Qualifier(value = "knihaService")
	CommonService<Book> knihaService;

	@Autowired
	@Qualifier(value = "napsalService")
	CommonService<Napsal> napsalService;

	@InitBinder
	public void initModel(WebDataBinder binder) {
		Object targer = binder.getTarget();
		if (targer instanceof AuthorView) {
			if (binder.getValidator() == null) {
				binder.setValidator(new AutorValidator());
			}
		}
	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView showList(HttpServletRequest request) {
		ModelAndView model = new ModelAndView("authors/showList");
		HttpSession session = request.getSession();
		String error = String.valueOf(session.getAttribute("error"));
		if(error!=null){
			model.addObject("error",error);
			session.removeAttribute("error");
		}
		try {
			List<Author> autorList = autorService.getAll();
			model.addObject("authorView", new AuthorView());
			model.addObject("autorList", autorList);
		} catch (DatabaseOperationException e) {
			log.error(e.getMessage(), e);
			model.addObject("error", e.getMessage());
		}
		return model;
	}
	
	@RequestMapping("/find")
	public ModelAndView find(HttpServletRequest request, AuthorView view) {
		ModelAndView model = new ModelAndView("authors/showList");
		try {
			if (view.getJmeno() != null && !view.getJmeno().equals("")  && view.getPrijmeni() == null && view.getPrijmeni().equals("") ) {
				model.addObject("authorView", new AuthorView());
				model.addObject("autorList", autorService.getByClause("and upper(jmeno_a) like '%" + view.getJmeno().toUpperCase() + "%'"));
			}else if (view.getJmeno() == null || view.getJmeno().equals("")  && view.getPrijmeni() != null && !view.getPrijmeni().equals("") ) {
				model.addObject("authorView", new AuthorView());
				model.addObject("autorList", autorService.getByClause("and upper(prijmeni_a) like '%" + view.getPrijmeni().toUpperCase() + "%'"));
			}else if (view.getJmeno() != null && !view.getJmeno().equals("")  && view.getPrijmeni() != null && !view.getPrijmeni().equals("") ) {
				model.addObject("authorView", new AuthorView());
				model.addObject("autorList", autorService.getByClause("and upper(prijmeni_a) like '%" + view.getPrijmeni().toUpperCase() + "%' and upper(jmeno_a) like '%" + view.getJmeno().toUpperCase() + "%'"));
			}else{
				List<Author> autorList = autorService.getAll();
				model.addObject("authorView", new AuthorView());
				model.addObject("autorList", autorList);
			}
		} catch (DatabaseOperationException e) {
			model.addObject("error", e.getMessage());
		}
		return model;
	}

	/**
	 * 
	 * @param request
	 * @param author
	 * @param error
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	@RequestMapping(value = "/submit", method = RequestMethod.POST)
	public ModelAndView addAutor(HttpServletRequest request, @Validated AuthorView authorView, BindingResult error)
			throws IllegalAccessException, InvocationTargetException {
		ModelAndView model = new ModelAndView();
		Author author = new Author();
		author.setJmeno(authorView.getJmeno());
		author.setPrijmeni(authorView.getPrijmeni());
		List<Napsal> napsalList = new ArrayList<Napsal>();
		try {
			if (!error.hasErrors()) {
				// insert or update
				if (request.getParameter("authorId") == null) {
					autorService.insertEntity(author);
					author.setId(autorService.getByClause(
				"and jmeno_a='" + author.getJmeno() + "' and prijmeni_a='" + author.getPrijmeni() + "' order by id").get(0).getId());
//					assembleAuthorsBooks(authorView, author, napsalList);
//					napsalService.batchInsert(napsalList);
				} else {
					Integer authorId = Integer.valueOf(request.getParameter("authorId"));
					author.setId(authorId);
					autorService.updateEntity(author);
					assembleAuthorsBooks(authorView, author, napsalList);
					List<Napsal> writeToDelete = new ArrayList<Napsal>();
					List<Napsal> alreadyInDb = napsalService.getByClause("and autor_id_a="+authorId);
					for (Napsal napsal : alreadyInDb) {
						for (Napsal napsal2 : napsalList) {
							if(napsal.getKniha().getId().equals(napsal2.getKniha().getId())){
								writeToDelete.add(napsal2);
								napsalList.remove(napsal2);
								break;
							}
						}
					}
					if(!writeToDelete.isEmpty()){
						napsalService.batchDelete(writeToDelete);
					}
					if(!napsalList.isEmpty()){
						napsalService.batchInsert(napsalList);
					}
				}
				return new ModelAndView(new RedirectView("show.do?authorId="+author.getId()));
			}
		} catch (DatabaseOperationException e) {
			log.error(e.getMessage(), e);
			request.getSession().setAttribute("error", e.getMessage());
		}
		if (request.getParameter("authorId") != null) {
			return new ModelAndView(new RedirectView("edit.do?authorId="+request.getParameter("authorId")));
		} else {
			return new ModelAndView(new RedirectView("new.do"));
		}
	}

	/**
	 * @param authorView
	 * @param author
	 * @param napsalList
	 */
	private void assembleAuthorsBooks(AuthorView authorView, Author author, List<Napsal> napsalList) {
		Author a = author.getId() == null ? autorService.getByClause(
				"and jmeno_a='" + author.getJmeno() + "' and prijmeni_a='" + author.getPrijmeni() + "'").get(0) : author;
		author.setId(a.getId());
		for (Integer knihaId : authorView.getKnihaIds()) {
			Napsal n = new Napsal();
			n.setAutor(a);
			n.setKniha(knihaService.getById(knihaId));
			napsalList.add(n);
		}
	}

	@RequestMapping("/new")
	public ModelAndView newAuthor(HttpServletRequest request) {
		ModelAndView model = new ModelAndView("authors/new");
		HttpSession session = request.getSession();
		String error = String.valueOf(session.getAttribute("error"));
		if(error != null){
			model.addObject("error", error);
			session.removeAttribute("error");
		}
		insertOrUpdate(request, model);
		return model;
	}

	/**
	 * 
	 * @param request
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	@RequestMapping(value = "/edit", method = RequestMethod.GET)
	public ModelAndView editAuthor(HttpServletRequest request) throws IllegalAccessException, InvocationTargetException {
		ModelAndView model = new ModelAndView();
		insertOrUpdate(request, model);
		return model;
	}

	@RequestMapping(value = "/delete", method = RequestMethod.GET)
	public ModelAndView deleteAuthor(HttpServletRequest request) {
		ModelAndView model = new ModelAndView("authors/showList");
		try {
			Integer authorId = Integer.valueOf(request.getParameter("authorId"));
			if (authorId != null) {
				Author a = new Author();
				a.setId(authorId);
				List<Napsal> napsal = napsalService.getByClause("and AUTOR_ID_A = " + authorId);
				napsalService.batchDelete(napsal);
				autorService.deleteEntity(a);
			}
		} catch (NumberFormatException e) {
			log.error(e.getMessage(), e);
			request.getSession().setAttribute("error", e.getMessage());
		}
		return new ModelAndView(new RedirectView("../authors.do"));
	}

	/**
	 * @param request
	 * @param model
	 */
	private void insertOrUpdate(HttpServletRequest request, ModelAndView model) {
		try {
			if (request.getParameter("authorId") != null) {
				Integer authorId = Integer.valueOf(request.getParameter("authorId"));
				model.addObject("author", setAuthorView(autorService.getById(authorId), model));
				model.setViewName("authors/edit");
			} else {
				model.addObject("author", new AuthorView());
				model.addObject("knihaList", knihaService.getAll());
				model.setViewName("authors/new");
			}
		} catch (DatabaseOperationException e) {
			log.error(e.getMessage(), e);
			model.addObject("error", e.getMessage());
		}
	}

	private AuthorView setAuthorView(Author author, ModelAndView model) {
		AuthorView view = new AuthorView();
		view.setJmeno(author.getJmeno());
		view.setPrijmeni(author.getPrijmeni());
		view.setId(author.getId());
		List<Napsal> napsalList = napsalService.getByClause("and autor_id_a = " + author.getId());
		List<Integer> knihaList = new ArrayList<Integer>();
		for (Napsal napsal : napsalList) {
			knihaList.add(napsal.getKniha().getId());
		}
		view.setKnihaIds(knihaList);
		view.setKnihaList(knihaService.getAll());
		return view;
	}

	/**
	 * 
	 * @param request
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	@RequestMapping(value = { "/show" }, method = RequestMethod.GET)
	public ModelAndView showAuthor(HttpServletRequest request) throws IllegalAccessException {
		ModelAndView model = new ModelAndView();
		try {
			Author a = autorService.getById(Integer.valueOf(request.getParameter("authorId")));
			model.addObject("author", a);
			List<Napsal> list = napsalService.getByClause("and autor_id_a = " + a.getId());
			List<Book> knihaList = new ArrayList<Book>();
			for (Napsal napsal : list) {
				knihaList.add(napsal.getKniha());
			}
			model.addObject("knihaList", knihaList);
		} catch (DatabaseOperationException e) {
			model.addObject("error", e.getMessage());
		}
		return model;
	}

	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

}
